home *** CD-ROM | disk | FTP | other *** search
- // This is part of the iostream library, providing input/output for C++.
- // Copyright (C) 1991 Per Bothner.
- //
- // This library is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Library General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- // You should have received a copy of the GNU Library General Public
- // License along with this library; if not, write to the Free
- // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- #pragma implementation
- #include "ioprivat.h"
- #include <iostream.h>
- #include <ctype.h>
- #include "floatio.h"
-
- #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
-
- //#define isspace(ch) ((ch)==' ' || (ch)=='\t' || (ch)=='\n')
-
- extern streambuf not_open_filebuf;
-
- int istream::good() // For now
- {
- return _strbuf != ¬_open_filebuf;
- }
-
- #ifdef OLD_STDIO
- int ostream::good() // For now
- {
- return _strbuf != ¬_open_filebuf;
- }
- #endif
-
- istream::istream() : ios(¬_open_filebuf)
- {
- _flags |= ios::dont_close;
- _gcount = 0;
- _tie = NULL;
- }
-
- istream::istream(streambuf *sb, ostream* tied) : ios(sb)
- {
- #if 0
- _flags |= ios::dont_close;
- #else
- _flags &= ~((unsigned long)(ios::dont_close));
- #endif
- _gcount = 0;
- _tie = tied;
- }
-
- void istream::close()
- {
- if (!(_flags & (unsigned int)ios::dont_close))
- delete _strbuf;
- _flags |= ios::dont_close;
- _strbuf = ¬_open_filebuf;
- }
-
- istream::~istream()
- {
- close();
- }
-
- int skip_ws(streambuf* sb)
- {
- int ch;
- for (;;) {
- ch = sb->sbumpc();
- if (ch == EOF || !isspace(ch))
- return ch;
- }
- }
-
- istream& istream::get(char& c)
- {
- if (ipfx1()) {
- int ch = _strbuf->sbumpc();
- if (ch == EOF) clear(rdstate()|ios::failbit);
- else c = (char)ch;
- }
- return *this;
- }
-
- istream& istream::get(unsigned char& c)
- {
- if (ipfx1()) {
- int ch = _strbuf->sbumpc();
- if (ch == EOF) clear(rdstate()|ios::failbit);
- else c = (unsigned char)ch;
- }
- return *this;
- }
-
- istream& istream::operator>>(char& c)
- {
- if (ipfx0()) {
- int ch = _strbuf->sbumpc();
- if (ch == EOF)
- clear(rdstate()|(ios::eofbit|ios::failbit));
- else
- c = (char)ch;
- }
- return *this;
- }
-
- istream& istream::operator>>(unsigned char& c)
- {
- if (ipfx0()) {
- int ch = _strbuf->sbumpc();
- if (ch == EOF)
- clear(rdstate()|(ios::eofbit|ios::failbit));
- else
- c = (unsigned char)ch;
- }
- return *this;
- }
-
- istream& istream::operator>>(char* ptr)
- {
- if (ipfx0()) {
- register streambuf* sb = _strbuf;
- int ch = sb->sbumpc();
- if (ch == EOF)
- clear(rdstate()|(ios::eofbit|ios::failbit));
- else {
- int w = width(0); // FIXME: Not used!
- *ptr++ = ch;
- for (;;) {
- ch = sb->sbumpc();
- if (ch == EOF)
- break;
- else if (isspace(ch)) {
- sb->sputbackc(ch);
- break;
- }
- }
- *ptr++ = 0;
- }
- }
- return *this;
- }
-
- static int read_int(istream& stream, unsigned long& val, int& neg)
- {
- if (!stream.ipfx0())
- return 0;
- register streambuf* sb = stream.rdbuf();
- int base = 10;
- int ndigits = 0;
- register int ch = skip_ws(sb);;
- if (ch == EOF)
- goto fail;
- neg = 0;
- if (ch == '+') {
- ch = skip_ws(sb);
- }
- else if (ch == '-') {
- neg = 1;
- ch = skip_ws(sb);
- }
- if (ch == EOF) goto fail;
- if (stream.flags() & (ios::hex|ios::dec|ios::oct)) {
- if (ch == '0') {
- ch = sb->sbumpc();
- if (ch == EOF) {
- val = 0;
- return 1;
- }
- if (ch == 'x' || ch == 'X') {
- base = 16;
- ch = sb->sbumpc();
- if (ch == EOF) goto fail;
- }
- else
- base = 8;
- }
- }
- else if (stream.flags() & ios::hex)
- base = 16;
- else if (stream.flags() & ios::oct)
- base = 8;
- val = 0;
- for (;;) {
- if (ch == EOF)
- break;
- int digit;
- if (ch >= '0' && ch <= '9')
- digit = ch - '0';
- else if (ch >= 'A' && ch <= 'F')
- digit = ch - 'A' + 10;
- else if (ch >= 'a' && ch <= 'f')
- digit = ch - 'a' + 10;
- else
- digit = 999;
- if (digit >= base)
- if (ndigits == 0) goto fail;
- else {
- sb->sputbackc(ch);
- return 1;
- }
- ndigits++;
- val = 10 * val + digit;
- ch = sb->sbumpc();
- }
- return 1;
- fail:
- stream.clear(stream.rdstate()|ios::failbit);
- return 0;
- }
-
- #define READ_INT(TYPE) \
- istream& istream::operator>>(TYPE& i)\
- {\
- unsigned long val; int neg;\
- if (read_int(*this, val, neg)) {\
- if (neg) val = -val;\
- i = (TYPE)val;\
- }\
- return *this;\
- }
-
- READ_INT(short)
- READ_INT(unsigned short)
- READ_INT(int)
- READ_INT(unsigned int)
- READ_INT(long)
- READ_INT(unsigned long)
-
- istream& istream::operator>>(double& x)
- {
- if (ipfx0()) {
- double* ptr = &x;
- __vsbscanf(rdbuf(), "%lg", (va_list)&ptr);
- }
- return *this;
- }
- istream& istream::operator>>(float& x)
- {
- if (ipfx0()) {
- float* ptr = &x;
- __vsbscanf(rdbuf(), "%g", (va_list)&ptr);
- }
- return *this;
- }
-
- inline ostream& ostream::operator<<(char c)
- {
- if (opfx()) {
- int w = width(0);
- char fill_char = fill();
- register int padding = w > 0 ? w - 1 : 0;
- if (!(flags() & ios::left)) // Default adjustment.
- while (--padding >= 0) _strbuf->sputc(fill_char);
- _strbuf->sputc(c);
- if (flags() & ios::left) // Left adjustment.
- while (--padding >= 0) _strbuf->sputc(fill_char);
- osfx();
- }
- return *this;
- }
-
- void write_int(ostream& stream, unsigned long val, int neg)
- {
- char buf[10 + sizeof(unsigned long) * 3];
- char *show_base = "";
- int show_base_len = 0;
- if ((stream.flags() & (ios::oct|ios::hex)) == 0) // Decimal
- sprintf(buf, "%lu", val);
- else if (stream.flags() & ios::oct) { // Oct
- sprintf(buf, "%lo", val);
- if (stream.flags() && ios::showbase)
- show_base = "0"; show_base_len = 1;
- }
- else if (stream.flags() & ios::uppercase) {// Hex
- sprintf(buf, "%lX", val);
- if (stream.flags() && ios::showbase)
- show_base = "0X"; show_base_len = 2;
- }
- else { // Hex
- sprintf(buf, "%lx", val);
- if (stream.flags() && ios::showbase)
- show_base = "0x"; show_base_len = 2;
- }
- int buf_len = strlen(buf);
- int w = stream.width(0);
- int show_pos = 0;
- int i;
-
- // Calculate padding.
- int len = buf_len;
- if (neg) len++;
- else if (val != 0 && (stream.flags() & ios::showpos)) len++, show_pos=1;
- len += show_base_len;
- int padding = len > w ? 0 : w - len;
-
- // Do actual output.
- register streambuf* sbuf = stream.rdbuf();
- unsigned long pad_kind =
- stream.flags() & (ios::left|ios::right|ios::internal);
- char fill_char = stream.fill();
- if (pad_kind != (unsigned long)ios::left // Default (right) adjustment.
- && pad_kind != (unsigned long)ios::internal)
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
- if (neg) sbuf->sputc('-');
- else if (show_pos) sbuf->sputc('+');
- if (show_base_len)
- sbuf->sputn(show_base, show_base_len);
- if (pad_kind == (unsigned long)ios::internal)
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
- sbuf->sputn(buf, buf_len);
- if (pad_kind == (unsigned long)ios::left) // Left adjustment.
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
- stream.osfx();
- }
-
- ostream& ostream::operator<<(int n)
- {
- if (opfx()) {
- if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0)
- write_int(*this, -n, 1);
- else
- write_int(*this, n, 0);
- }
- return *this;
- }
-
- ostream& ostream::operator<<(long n)
- {
- if (opfx()) {
- if (n < 0 && (flags() & (ios::oct|ios::hex)) == 0)
- write_int(*this, -n, 1);
- else
- write_int(*this, n, 0);
- }
- return *this;
- }
-
- ostream& ostream::operator<<(unsigned int n)
- {
- if (opfx())
- write_int(*this, n, 0);
- return *this;
- }
-
- ostream& ostream::operator<<(unsigned long n)
- {
- if (opfx())
- write_int(*this, n, 0);
- return *this;
- }
-
- ostream& ostream::operator<<(float n)
- {
- return *this << (double)n;
- }
-
- ostream& ostream::operator<<(double n)
- {
- if (opfx()) {
- // Uses __cvt_double (renamed from static cvt), in Chris Torek's
- // stdio implementation. The setup code uses the same logic
- // as in __vsbprintf.C (also based on Torek's code).
- char negative;
- char buf[BUF];
- int format_char;
- int sign = '\0';
- #if 0
- if (flags() ios::showpos) sign = '+';
- #endif
- if (flags() & ios::fixed)
- format_char = 'f';
- else if (flags() & ios::scientific)
- format_char = flags() & ios::uppercase ? 'E' : 'e';
- else
- format_char = flags() & ios::uppercase ? 'G' : 'g';
-
- int fpprec = 0; // 'Extra' (suppressed) floating precision.
- int prec = precision();
- if (prec < 0) prec = 6; // default.
- else if (prec > MAXFRACT) {
- if (flags() & (ios::fixed|ios::scientific) & ios::showpos)
- fpprec = prec - MAXFRACT;
- prec = MAXFRACT;
- }
-
- // Do actual conversion.
- char *cp = buf;
- *cp = 0;
- int size = __cvt_double(n, precision(),
- flags() & ios::showpoint ? 0x80 : 0,
- &negative,
- format_char, cp, buf + sizeof(buf));
- if (negative) sign = '-';
- if (*cp == 0)
- cp++;
-
- // Calculate padding.
- int fieldsize = size + fpprec;
- if (sign) fieldsize++;
- int padding = 0;
- int w = width(0);
- if (fieldsize < w)
- padding = w - fieldsize;
-
- // Do actual output.
- register streambuf* sbuf = rdbuf();
- register i;
- char fill_char = fill();
- unsigned long pad_kind =
- flags() & (ios::left|ios::right|ios::internal);
- if (pad_kind != (unsigned long)ios::left // Default (right) adjust.
- && pad_kind != (unsigned long)ios::internal)
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
- if (sign)
- sbuf->sputc(sign);
- if (pad_kind == (unsigned long)ios::internal)
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
-
- // Emit the actual concented field, followed by extra zeros.
- sbuf->sputn(cp, size);
- for (i = fpprec; --i >= 0; ) sbuf->sputc('0');
-
- if (pad_kind == (unsigned long)ios::left) // Left adjustment
- for (i = padding; --i >= 0; ) sbuf->sputc(fill_char);
- osfx();
- }
- return *this;
- }
-
- inline ostream& ostream::operator<<(const char *s)
- {
- if (opfx()) {
- int len = strlen(s);
- int w = width(0);
- char fill_char = fill();
- register int padding = w > len ? w - len : 0;
- if (!(flags() & ios::left)) // Default adjustment.
- while (--padding >= 0) _strbuf->sputc(fill_char);
- _strbuf->sputn(s, len);
- if (flags() & ios::left) // Left adjustment.
- while (--padding >= 0) _strbuf->sputc(fill_char);
- osfx();
- }
- return *this;
- }
-
- ostream& ostream::operator<<(void *p)
- {
- if (opfx()) {
- __sbprintf(_strbuf, "0x%x", p);
- osfx();
- }
- return *this;
- }
-
- ostream& ostream::operator<<(register streambuf* sbuf)
- {
- if (opfx()) {
- register streambuf* outbuf = rdbuf();
- // NOTE: Should optimize!
- for (;;) {
- register int ch = sbuf->sbumpc();
- if (ch == EOF) break;
- outbuf->sputc(ch);
- }
- osfx();
- }
- return *this;
- }
-
- ostream::ostream() : ios(¬_open_filebuf)
- {
- _flags |= ios::dont_close;
- _tie = NULL;
- }
-
- ostream::ostream(streambuf* sb, ostream* tied) : ios(sb)
- {
- #if 0
- _flags |= ios::dont_close;
- #else
- _flags &= ~((unsigned long)(ios::dont_close));
- #endif
- _tie = tied;
- }
-
- void ostream::close()
- {
- if (!(_flags & (unsigned int)ios::dont_close))
- delete _strbuf;
- _flags |= ios::dont_close;
- _strbuf = ¬_open_filebuf;
- }
-
- ostream::~ostream()
- {
- close();
- }
-
- ostream& ostream::form(const char *format ...)
- {
- va_list ap;
- va_start(ap, format);
- __vsbprintf(_strbuf, format, ap);
- va_end(ap);
- return *this;
- }
-
- inline ostream& ostream::flush()
- {
- if (_strbuf->sync())
- clear(rdstate() | ios::badbit);
- return *this;
- }
-
- #ifndef IMPLEMENT_STDIO
- extern streambuf CIN_STREAMBUF[1];
- extern streambuf COUT_STREAMBUF[1];
- extern streambuf CERR_STREAMBUF[1];
- #define CLOG_STREAMBUF CERR_STREAMBUF
- #endif
-
- istream cin((streambuf*)CIN_STREAMBUF, &cout);
- ostream cout((streambuf*)COUT_STREAMBUF);
- ostream cerr((streambuf*)CERR_STREAMBUF, &cout);
- ostream clog((streambuf*)CLOG_STREAMBUF, &cout);
-
- ostream& flush(ostream& outs)
- {
- outs.rdbuf()->overflow(EOF);
- return outs;
- }
-
- istream& ws(istream& ins)
- {
- #if 1
- for (;;) {
- int ch = ins._strbuf->sbumpc();
- if (ch == EOF) break;
- if (isspace(ch)) continue;
- ins._strbuf->sputbackc(ch);
- break;
- }
- #else
- int ch = ins._strbuf->sgetc();
- while (ch != EOF && isspace(ch))
- ch = ins._strbuf->snextc();
- #endif
- return ins;
- }
-
- ostream& ends(ostream& outs)
- {
- outs.put(0);
- return outs;
- }
-
- ostream& endl(ostream& outs)
- {
- return flush(outs.put('\n'));
- }
-
- void ostream::do_osfx()
- {
- if (flags() & ios::unitbuf)
- flush();
- if (flags() & ios::stdio) {
- fflush(stdout);
- fflush(stderr);
- }
- }
-
- static const unsigned long ios::basefield = ios::hex|ios::oct|ios::dec;
- static const unsigned long ios::floatfield = ios::scientific|ios::fixed;
- static const unsigned long ios::adjustfield =
- ios::left|ios::right|ios::internal;
-